#include "GameSettings.h"
#include <QSettings>
#include <QInputDialog>
#include "../Utils/Msg.h"
#include "../Utils/SequentialRandom.h"
#include <QProcess>

GameSettings *GameSettings::mpMe = NULL;

GameSettings::GameSettings(QObject *parent):QObject(parent),mbSettingsLoaded(false)
{
    loadPreference();
    everFirstTimeSetting();
    setPlayerTurn(Game::Player1);
    mbSettingsLoaded = true;
}

void GameSettings::loadPreference()
{
    QSettings pre;//("kernel.writer@gmail.com","DotGame");

    setPlayWithComputer(pre.value("PlayWithComputer/Player",true).toBool());

    setPlayerColor(Game::Player1,pre.value("Color/1/Player",QColor(255,85,0)).value<QColor>());
    setPlayerColor(Game::Player2,pre.value("Color/2/Player",QColor(2,133,255)).value<QColor>());
    setPlayerColor(Game::Unknown,pre.value("Color/Unknown/Player",Qt::darkGray).value<QColor>());
    setPlayerName(Game::Player1,pre.value("Name/1/Player",QString("Player 1")).value<QString>());
    setPlayerName(Game::Player2,pre.value("Name/2/Player",QString("Computer")).value<QString>());
    setPlayerName(Game::Unknown,pre.value("Name/Unknown/Player",QString("Unknown")).value<QString>());

    setSetting(Game::BGColor,pre.value("Color/BG/Game",QColor(204,182,130)).value<QColor>());
    setSetting(Game::FieldColor,pre.value("Color/Field/Game",QColor(221,221,221)).value<QColor>());
    setSetting(Game::DotNormalColor,pre.value("Color/DotNormal/Game",QColor(161,0,0)).value<QColor>());
    setSetting(Game::DotUsedColor,pre.value("Color/DotUsed/Game",Qt::red).value<QColor>());
    setSetting(Game::DotSelectedColor,pre.value("Color/DotSelected/Game",QColor(255,255,127)).value<QColor>());
    setSetting(Game::DotSelectableColor,pre.value("Color/DotSelectable/Game",Qt::green).value<QColor>());
    setSetting(Game::PointMovable,pre.value("Color/DotMovable/Game",Qt::black).value<QColor>());

    setSetting(Game::DotsPerRow,pre.value("Integer/DotsPerRow/Game",10).value<uint>());
    setSetting(Game::DotsPerColumn,pre.value("Integer/DotsPerColumn/Game",8).value<uint>());
    setSetting(Game::CellWidth,pre.value("Integer/CellWidth/Game",60).value<uint>());
    setSetting(Game::CellHeight,pre.value("Integer/CellHeight/Game",60).value<uint>());
    setSetting(Game::DotRadii,pre.value("Integer/DotRadii/Game",10).value<uint>());
    setSetting(Game::PenWidth,pre.value("Integer/PenWidth/Game",3).value<uint>());
    setSetting(Game::FieldMargin,pre.value("Integer/FieldMargin/Game",20).value<uint>());
    setSetting(Game::WindowPosition,pre.value("Position/MainWindow",QPoint(0,0)).value<QPoint>());
    setSetting(Game::WindowSize,pre.value("Size/MainWindow",QSize(850,600)).value<QSize>());
    setSetting(Game::CtrlPnlVisible,pre.value("CtrlPnlVisible/MainWindow",true).value<bool>());
    setSetting(Game::CtrlPnlArea,pre.value("CtrlPnlArea/MainWindow",1).value<int>());
    setSetting(Game::BuddyPnlVisible,pre.value("BuddyPnlVisible/MainWindow",true).value<bool>());
    setSetting(Game::BuddyPnlArea,pre.value("BuddyPnlArea/MainWindow",2).value<int>());
    setSetting(Game::PlayingLevel,pre.value("PlayingLevel/Game",0).value<int>());
    setSetting(Game::ProgressBar,pre.value("Color/Progressbar_/Game",QColor(212,155,9)).value<QColor>());
    setSetting(Game::BlockOthersWhileNetPlay,pre.value("BlockOthersWhileNetPlay/Game",true).value<bool>());


    setPlayWithComputer(true);

    setIntegerSettingRange(Game::DotsPerRow,QPoint(2,100));
    setIntegerSettingRange(Game::DotsPerColumn,QPoint(2,100));
    setIntegerSettingRange(Game::CellWidth,QPoint(30,200));
    setIntegerSettingRange(Game::CellHeight,QPoint(30,200));
    setIntegerSettingRange(Game::FieldMargin,QPoint(20,500));
    rethinkAboutSomeIntergerSettingsRange();
}

void GameSettings::rethinkAboutSomeIntergerSettingsRange()
{
    int nCellWidth = setting(Game::CellWidth).value<uint>();
    int nCellHeight = setting(Game::CellHeight).value<uint>();
    int nWall = nCellWidth > nCellHeight ? nCellHeight : nCellWidth;
    nWall = nWall / 2;

    int nDotRadii = setting(Game::DotRadii).value<uint>();

    if(nDotRadii > nWall){
        setSetting(Game::DotRadii,nWall);
    }

    setIntegerSettingRange(Game::DotRadii,QPoint(6,nWall));

    int nPenWidth = setting(Game::PenWidth).value<uint>();

    if(nPenWidth > nWall){
        setSetting(Game::PenWidth,nWall);
    }

    setIntegerSettingRange(Game::PenWidth,QPoint(1,nWall));
}

GameSettings *GameSettings::me()
{
    if(mpMe == NULL){
        mpMe = new GameSettings();
    }

    return mpMe;
}

void GameSettings::setPlayerColor(Game::Player player, QColor color)
{
    if(mPlayerColors[int(player)] != color){
        mPlayerColors[int(player)] = color;
        emit playerColorChanged(player);
        emit settingChanged();
    }
}

QColor GameSettings::playerColor(Game::Player player)
{
    return mPlayerColors[int(player)];
}

void GameSettings::setPlayerName(Game::Player player, QString name)
{
    if(mPlayerName[int(player)] != name){
        mPlayerName[int(player)] = name;
        emit playerNameChanged(player);
        emit settingChanged();
    }
}

QString GameSettings::playerName(Game::Player player)
{
    return mPlayerName[int(player)];
}

void GameSettings::setSetting(Game::Setting settingName, QVariant value)
{
    if(mSettingsMap[int(settingName)] != value){
        mSettingsMap[int(settingName)] = value;
        emit gameSettingChanged(settingName);
        emit settingChanged();

        if(mbSettingsLoaded && (settingName == Game::CellWidth || settingName == Game::CellHeight)){
            rethinkAboutSomeIntergerSettingsRange();
        }
    }
}

QVariant GameSettings::setting(Game::Setting settingName)
{
    if(mSettingsMap.contains(int(settingName))){
        return mSettingsMap[settingName];
    }
    else{
        return defaultValue(settingName);
    }
}

QVariant GameSettings::defaultValue(Game::Setting settingName)
{
    if(settingName >= UIntStart && settingName <= UIntEnd){
        return QVariant(uint(0));
    }
    else if(settingName >= ColorStart && settingName <= ColorEnd){
        return QVariant(QColor(0,0,0));
    }

    return QVariant();
}

QLinearGradient GameSettings::brush(Game::Setting  settingName)
{
    if(settingName >= ColorStart && settingName <= ColorEnd){
        return brush(setting(settingName).value<QColor>());
    }

    return brush(QColor(0,0,0));
}

QLinearGradient GameSettings::brush(Game::Player player)
{
    return brush(playerColor(player));
}

QLinearGradient GameSettings::brush(QColor color)
{
    QLinearGradient linearGradient(0, 0, 20, 20);
    linearGradient.setColorAt(0.0, color);
    linearGradient.setColorAt(1.0, color);

    return linearGradient;
}

QPen GameSettings::pen(Game::Setting  settingName)
{
    if(settingName >= ColorStart && settingName <= ColorEnd){
        return pen(setting(settingName).value<QColor>());
    }

    return pen(QColor(0,0,0));
}

QPen GameSettings::pen(Game::Player player)
{
    return pen(playerColor(player));
}

QPen GameSettings::pen(QColor color)
{
    QPen p(color,setting(Game::PenWidth).value<int>());

    return p;
}

void GameSettings::setPlayerTurn(Game::Player player)
{
    mPlayerTurn = player;
}

Game::Player GameSettings::playerTurn(){return mPlayerTurn;}

void GameSettings::savePreference()
{
    QSettings pre;//("kernel.writer@gmail.com","DotGame");

    pre.setValue("PlayWithComputer/Player",playingWithComputer());

    pre.setValue("Color/1/Player",playerColor(Game::Player1));
    pre.setValue("Color/2/Player",playerColor(Game::Player2));
    pre.setValue("Color/Unknown/Player",playerColor(Game::Unknown));
    pre.setValue("Name/1/Player",playerName(Game::Player1));
    pre.setValue("Name/2/Player",playerName(Game::Player2));
    pre.setValue("Name/Unknown/Player",playerName(Game::Unknown));

    pre.setValue("Color/BG/Game",setting(Game::BGColor));
    pre.setValue("Color/Field/Game",setting(Game::FieldColor));
    pre.setValue("Color/DotNormal/Game",setting(Game::DotNormalColor));
    pre.setValue("Color/DotUsed/Game",setting(Game::DotUsedColor));
    pre.setValue("Color/DotSelected/Game",setting(Game::DotSelectedColor));
    pre.setValue("Color/DotSelectable/Game",setting(Game::DotSelectableColor));
    pre.setValue("Color/DotMovable/Game",setting(Game::PointMovable));

    pre.setValue("Integer/DotsPerRow/Game",setting(Game::DotsPerRow));
    pre.setValue("Integer/DotsPerColumn/Game",setting(Game::DotsPerColumn));
    pre.setValue("Integer/CellWidth/Game",setting(Game::CellWidth));
    pre.setValue("Integer/CellHeight/Game",setting(Game::CellHeight));
    pre.setValue("Integer/DotRadii/Game",setting(Game::DotRadii));
    pre.setValue("Integer/PenWidth/Game",setting(Game::PenWidth));
    pre.setValue("Integer/FieldMargin/Game",setting(Game::FieldMargin));
    pre.setValue("Position/MainWindow",setting(Game::WindowPosition));
    pre.setValue("Size/MainWindow",setting(Game::WindowSize));
    pre.setValue("CtrlPnlVisible/MainWindow",setting(Game::CtrlPnlVisible));
    pre.setValue("CtrlPnlArea/MainWindow",setting(Game::CtrlPnlArea));
    pre.setValue("BuddyPnlVisible/MainWindow",setting(Game::BuddyPnlVisible));
    pre.setValue("BuddyPnlArea/MainWindow",setting(Game::BuddyPnlArea));
    pre.setValue("PlayingLevel/Game",setting(Game::PlayingLevel));

    pre.setValue("Color/Progressbar_/Game",setting(Game::ProgressBar));
    pre.setValue("BlockOthersWhileNetPlay/Game",setting(Game::BlockOthersWhileNetPlay));
}


void GameSettings::setMostTopWnd(QWidget *pWnd)
{
    mpMostParentWnd = pWnd;
}

QWidget *GameSettings::mostTopWnd()const{return mpMostParentWnd;}

bool GameSettings::inputFromUserToSelectTurn()
{
    QStringList players;
    players << GameSettings::me()->playerName(Game::Player1) << GameSettings::me()->playerName(Game::Player2);
    bool bOk = false;
    QString player;

    player = QInputDialog::getItem(GameSettings::me()->mostTopWnd(),tr("Choose a player to start the game"),tr("Select Player"),players,0,false,&bOk);

    if(!bOk || player.isEmpty()){
        return false;
    }

    if(player == GameSettings::me()->playerName(Game::Player1)){
        GameSettings::me()->setPlayerTurn(Game::Player1);
    }
    else{
        GameSettings::me()->setPlayerTurn(Game::Player2);
    }

    return true;
}

bool GameSettings::playingWithComputer() { return mbPlayWithComputer; }

void GameSettings::setPlayWithComputer(bool bPlay){mbPlayWithComputer = bPlay;}


void GameSettings::setIntegerSettingRange(Game::Setting setting,const QPoint value)
{
    if(setting >= Game::DotsPerRow && setting <= Game::FieldMargin){
        mIntegerSettingRanges[int(setting)] = value;
    }
}

QPoint GameSettings::integerSettingRange(Game::Setting setting)const
{
    if(setting >= Game::DotsPerRow && setting <= Game::FieldMargin){
        return mIntegerSettingRanges[int(setting)];
    }

    return QPoint(0,0);
}

QString GameSettings::modeName()
{
    QString strName;
    Game::GameLevel level = Game::GameLevel(setting(Game::PlayingLevel).value<int>());

    if(level == Game::Learning){
        strName = QString("Learning");
    }
    else{
        strName = QString("Playing");
    }

    return strName;
}

void GameSettings::everFirstTimeSetting()
{
    QString player1Name = playerName(Game::Player1);

    if(player1Name.toLower() == QString("player 1")){
        //Color
        SequentialRandom rnd(255,0);
        setPlayerColor(Game::Player1,QColor(rnd.next(),rnd.next(),rnd.next()));
        //Name
        QString strPCName;
        QStringList envVariables;
        envVariables << "USERNAME.*" << "USER.*" << "USERDOMAIN.*"
                     << "HOSTNAME.*" << "DOMAINNAME.*";

        QStringList environment = QProcess::systemEnvironment();
        foreach (QString string, envVariables) {
            int index = environment.indexOf(QRegExp(string));
            if (index != -1) {
                QStringList stringList = environment.at(index).split("=");
                if (stringList.size() == 2) {
                    strPCName = stringList.at(1).toUtf8();
                    break;
                }
            }
        }

        if(strPCName.isNull() || strPCName.isEmpty())
        {
            strPCName = tr("Player 1");
        }

        setPlayerName(Game::Player1,strPCName);
    }
}
